package com.tsugun.mediaplayer.view.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.tsugun.mediaplayer.R;

/**
 * 弧形进度条
 * Created by shize on 2017/3/18.
 */

public class ArcProgressBar extends View implements View.OnTouchListener {

    private static final int DEFAULT_HEIGHT = 200;
    private static final int DEFAULT_WIDTH = 200;
    private static final int DEFAULT_ANGLE = 120;
    private static final int DEFAULT_MAX = 100;
    private static final int DEFAULT_CRRENT = 0;
    private static final int DEFAULT_CRRENT_WIDTH = 10;

    private int mAngle; // 进度容器角度
    private float mMax; //最大值
    private float mCrrent; // 当前值
    private float mRadius; // 圆的半径
    private int mBackgroundProgress; // 进度背景色
    private int mBackgroundMax; // 容器背景色
    private int mProgressWidth; // 进度条宽度
    private int mStartAngle; // 开始角度位置
    private int mOffset; // 与画板的间距

    private int mWidth; // 控件宽度
    private int mHeight; // 控件高度
    private Paint mProgressPaint; // 进度画笔
    private Paint mMaxPaint; // 最大值画笔
    private RectF mRectF; // 弧形外切矩形

    private float mDownX; // 按下X的坐标
    private float mDownY; // 按下Y的坐标
    private float mLastX; // 上一次按下的X的坐标
    private float mLastY; // 上一次按下的Y的坐标
    private float mTouchWidth; // 可有效触碰的宽度
    private boolean mIsPosition; // 记录第一次按下是否为可触摸范围

    private float mCenterY; // 圆心坐标
    private float mCenterX;
    private float mTouchAngle; // 触摸点相对起始点的角度

    public ArcProgressBar(Context context) {
        super(context);
    }

    public ArcProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initData(context, attrs);
    }

    public ArcProgressBar(Context context, AttributeSet attrs, int def) {
        super(context, attrs, def);
        initData(context, attrs);
    }

    /**
     * 初始化数据
     *
     * @param context 上下文
     * @param attrs   自定义属性
     */
    private void initData(final Context context, @Nullable AttributeSet attrs) {
        // 设置用户在XML中使用的属性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
        if (ta != null) {
            mAngle = ta.getInt(R.styleable.ArcProgressBar_angle, DEFAULT_ANGLE);
            mMax = ta.getFloat(R.styleable.ArcProgressBar_valueMax, DEFAULT_MAX);
            mCrrent = ta.getFloat(R.styleable.ArcProgressBar_valueCurrent, DEFAULT_CRRENT);
            mBackgroundProgress = ta.getColor(R.styleable.ArcProgressBar_backgroundBarProgress,
                    Color.RED);
            mBackgroundMax = ta.getColor(R.styleable.ArcProgressBar_backgroundBarMax, Color.GRAY);
            mProgressWidth = ta.getInt(R.styleable.ArcProgressBar_progressWidth, DEFAULT_CRRENT_WIDTH);
            mStartAngle = ta.getInt(R.styleable.ArcProgressBar_startAngle, getStartAngle());
            mOffset = ta.getInt(R.styleable.ArcProgressBar_offset, mProgressWidth / 2);
            mRadius = ta.getFloat(R.styleable.ArcProgressBar_radius, 200);
            ta.recycle();
        } else {
            mAngle = DEFAULT_ANGLE;
            mMax = DEFAULT_MAX;
            mCrrent = DEFAULT_CRRENT;
            mBackgroundProgress = Color.RED;
            mBackgroundMax = Color.GRAY;
            mProgressWidth = DEFAULT_CRRENT_WIDTH;
            mStartAngle = getStartAngle();
            mOffset = mProgressWidth / 2;
            mRadius = 200;
        }
    }

    /**
     * 计算并获取起始位置
     *
     * @return 起始位置
     */
    protected int getStartAngle() {
        return ((360 - mAngle) - 180) / 2;
    }

    /**
     * 设置进度条外接长方形
     */
    private void setRectF() {
        int offset = mProgressWidth + mOffset;
        float diameter = mRadius * 2; // 直径
        float left, top, right, bottom;
        if (mWidth > mHeight) {
            top = mHeight - diameter + offset;
            bottom = mHeight - offset;
            left = (mWidth - diameter) / 2 + offset;
            right = mWidth - left;
        } else {
            top = (mHeight - diameter) / 2 + offset;
            bottom = mHeight - top;
            left = mWidth - diameter + offset;
            right = mWidth - offset;
        }
        mRectF = new RectF(left, top, right, bottom);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 设置默认大小为200px
        setMeasuredDimension(measureSizeWithDefault(DEFAULT_HEIGHT, widthMeasureSpec),
                measureSizeWithDefault(DEFAULT_WIDTH, heightMeasureSpec));
    }

    /**
     * 带默认值的测量
     *
     * @return 尺寸值
     */
    private int measureSizeWithDefault(int defaultSize, int measureSpec) {
        int result = MeasureSpec.getSize(measureSpec);
        int specMode = MeasureSpec.getMode(measureSpec);
        // 测量返回，如果自适应则返回默认值
        return (specMode == MeasureSpec.EXACTLY) ? result : (specMode == MeasureSpec.AT_MOST) ?
                Math.min(defaultSize, result) : defaultSize;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawArc(mRectF, mStartAngle, mAngle, false, mMaxPaint);
        // 此处加0.01f为了防止绘制椭圆bug
        canvas.drawArc(mRectF, mStartAngle, mAngle * (mCrrent / mMax) + 0.01f, false, mProgressPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mHeight = h;
        mWidth = w;
        initProgressBar();
    }

    /**
     * 初始化工具
     */
    private void initProgressBar() {
        mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressPaint.setColor(mBackgroundProgress);
        mProgressPaint.setStrokeWidth(mProgressWidth);
        mProgressPaint.setStyle(Paint.Style.STROKE);

        mMaxPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMaxPaint.setColor(mBackgroundMax);
        mMaxPaint.setStrokeWidth(mProgressWidth);
        mMaxPaint.setStyle(Paint.Style.STROKE);

        mTouchWidth = mProgressWidth + (mOffset * 2);
        setRectF();

        // 圆心的Y轴坐标
        mCenterY = mHeight - (mRadius + (mTouchWidth / 2));
        // 圆心x轴坐标
        mCenterX = mWidth / 2;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                setDownEvent(event);
                break;
            case MotionEvent.ACTION_MOVE:
                setMoveEvent(event);
                break;
            case MotionEvent.ACTION_UP:
                setUpEvent(event);
                break;
        }
        // 如果不在触摸范围就不做事件拦截
        return mIsPosition;
    }

    /**
     * 按下事件
     *
     * @param event 事件
     */
    private void setDownEvent(MotionEvent event) {
        mDownX = event.getX();
        mDownY = event.getY();
        // 检测按下位置
        checkTouchPosition(mDownX, mDownY);
        setProgress(event);
    }

    /**
     * 检测触摸位置
     */
    private void checkTouchPosition(float touchX, float touchY) {
        float x = touchX - mCenterX;
        float y = touchY - mCenterY;
        // 计算触摸点的斜边长度
        double touchBevel = Math.sqrt((x * x) + (y * y));
        // 计算最外层该条线上的斜边长度
        double outBevel = mRadius + mTouchWidth;
        // 计算最内层该条线上的斜边长度
        double inBevel = mRadius - mTouchWidth;
        mIsPosition = (touchBevel >= inBevel && touchBevel <= outBevel);
    }

    /**
     * 移动事件
     *
     * @param event 事件
     */
    private void setMoveEvent(MotionEvent event) {
        setProgress(event);
    }

    /**
     * 设置进度
     *
     * @param event 事件
     */
    private void setProgress(MotionEvent event) {
        float touchX = event.getX();
        float touchY = event.getY();
        checkTouchPosition(touchX, touchY);
        if (mIsPosition) {
            // 利用角度比例计算触摸位置
            setAngleMethod(touchX, touchY);
            mLastX = touchX;
            mLastY = touchY;
        }
    }

    /**
     * 放开事件
     *
     * @param event 事件
     */
    private void setUpEvent(MotionEvent event) {
    }


    /**
     * 利用角度比例计算触摸位置
     *
     * @param touchX 触摸点x轴坐标
     * @param touchY 触摸点y轴坐标
     */
    private void setAngleMethod(float touchX, float touchY) {
        setTouchAngle(touchX, touchY);
        float radio = mTouchAngle / mAngle;
        setCrrent(radio * mMax);
    }

    /**
     * 计算触摸角度
     *
     * @param touchX 触摸点x轴坐标
     * @param touchY 触摸点y轴坐标
     */
    private void setTouchAngle(float touchX, float touchY) {
        // 相对圆心坐标（注意：屏幕坐标系的y轴向下为正方向）
        float x = touchX - mCenterX;
        float y = mCenterY - touchY;
        // 触摸点相对与X轴的角度
        float touchAngle = (float) Math.toDegrees(Math.atan(Math.abs(y) / Math.abs(x)));
        // 起始点相对y轴上方角度（设起始点不大于180°）
        float startAngle = 90 + mStartAngle;
        if (x > 0 && y > 0) {
            // 第一象限
            // 触摸点相对y轴上方角度，便于与起始点计算(其他象限同理)
            mTouchAngle = 90 - touchAngle;
        } else if (x < 0 && y > 0) {
            // 第二象限
            mTouchAngle = 270 + touchAngle;
        } else if (x < 0 && y < 0) {
            // 第三象限
            mTouchAngle = 270 - touchAngle;
        } else {
            // 第四象限
            mTouchAngle = 90 + touchAngle;
        }
        // 再计算触摸点相对起始点角度
        mTouchAngle = mTouchAngle - startAngle;
    }

    /**
     * @param mAngle 扇形弧度
     */
    public void setAngle(int mAngle) {
        this.mAngle = mAngle;
    }

    /**
     * @param mMax 最大进度值
     */
    public void setMax(int mMax) {
        this.mMax = mMax;
    }

    /**
     * @param mCrrent 进度值
     */
    public void setCrrent(float mCrrent) {
        if (mCrrent > mMax) {
            this.mCrrent = mMax;
        } else if (mCrrent < 0) {
            this.mCrrent = 0;
        } else {
            this.mCrrent = mCrrent;
        }
        invalidate();
    }

    /**
     * @return 当前进度值
     */
    public float getCrrent() {
        return mCrrent;
    }

    /**
     * @param mBackgroundProgress 当前进度颜色
     */
    public void setBackgroundProgress(int mBackgroundProgress) {
        this.mBackgroundProgress = mBackgroundProgress;
    }

    /**
     * @param mBackgroundMax 总进度颜色
     */
    public void setBackgroundMax(int mBackgroundMax) {
        this.mBackgroundMax = mBackgroundMax;
    }

    /**
     * @param mProgressWidth 进度条宽度
     */
    public void setProgressHeight(int mProgressWidth) {
        this.mProgressWidth = mProgressWidth;
    }

    /**
     * @param startAngle 起始角度（相对于x轴）
     */
    public void setStartAngle(int startAngle) {
        mStartAngle = startAngle;
    }

    /**
     * @param radius 半径
     */
    public void setRadius(int radius) {
        mRadius = radius;
    }

    /**
     * 开启触摸事件
     */
    public void openTouch() {
        setOnTouchListener(this);
    }
}
